# -*- coding:utf-8 -*-

import datetime
from iHome import constants
from flask import request, g, jsonify, current_app, session
from iHome.constants import AREA_INFO_REDIS_EXPIRES, HOUSE_DETAIL_REDIS_EXPIRE_SECOND, HOME_PAGE_MAX_HOUSES, HOME_PAGE_DATA_REDIS_EXPIRES, HOUSE_LIST_PAGE_CAPACITY
from iHome.utils.common import login_required
from iHome.utils.image_storage import storage
from . import api
from iHome import redis_store, db
from iHome.utils.response_code import RET
from iHome.models import Area, Facility, User, House, HouseImage, Order


@api.route('/houses/landlord')
@login_required
def search_landlord_house():
    """
    1.获取用户user_id
    2.根据user_id查询该用户名下的房屋信息
    3.返回给客户端
    :return: 
    """
    user_id = g.user_id
    try:
        houses = House.query.filter(House.user_id==user_id).all()
        print(houses)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库查询错误")
    houses_list = [house.to_basic_dict() for house in houses]
    return jsonify(errno=RET.OK, errmsg="OK", data=houses_list)


@api.route('/houses')
def search_house():
    """
    var params = {
        aid:areaId,
        sd:startDate,
        ed:endDate,
        sk:sortKey,
        p:next_page
    };
    :return:
    """
    args = request.args
    # 区域的id
    aid = args.get("aid", "")
    print('aid---->' + aid)
    # 用户过滤的开始入住日期和结束入住日期
    start_date_str = args.get("sd", "")
    print('sd---->' + start_date_str)
    end_date_str = args.get("ed", "")
    print('ed--->' + end_date_str)
    sk = args.get("sk", "new")
    print('sk--->' + sk)
    p = args.get("p", '1')
    print('p--->' + p)

    # 参数判断
    start_date = None
    end_date = None
    try:
        if start_date_str:
            start_date = datetime.datetime.strptime(start_date_str, "%Y-%m-%d")
        if end_date_str:
            end_date = datetime.datetime.strptime(end_date_str, "%Y-%m-%d")
        if end_date and start_date:
            assert start_date < end_date, Exception("开始时间不能大于结束时间")
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数有误")

    try:
        p = int(p)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg="参数有误")

    # 从redis中读取房屋数据
    try:
        redis_key = "house_list_%s_%s_%s_%s" % (
            aid, start_date_str, end_date_str, sk)
        response_dict = redis_store.hget(redis_key, p)
        if response_dict:
            return jsonify(errno=RET.OK, errmsg="OK", data=eval(response_dict))
    except Exception as e:
        current_app.logger.error(e)

    # 先把所有的房屋都查询出来并返回
    try:
        house_query = House.query
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据查询失败")

    # 过滤条件的列表
    filters = []
    if aid:
        # 添加过滤条件
        filters.append(House.area_id == aid)
    """
    Order.begin_date < end_date and Order.end_date > start_date
    所以要查询出所有的冲突的订单
    取到这些冲突订单的房屋id > [1,4,7]
    去房屋表中查: 不包含冲突订单的房屋id的数据 House.query.filter(House.id.notin_([1,4,7])
    """
    # 定义冲突的订单
    conflict_order = None
    if start_date and end_date:
        conflict_order = Order.query.filter(
            Order.begin_date < end_date,
            Order.end_date > start_date).all()
    elif start_date:
        conflict_order = Order.query.filter(Order.end_date > start_date).all()
    elif end_date:
        conflict_order = Order.query.filter(Order.begin_date < end_date).all()
    if conflict_order:
        # 取到这些冲突订单的房屋id > {1,4,7]
        conflict_house_ids = [order.house_id for order in conflict_order]
        # 不包含冲突订单的房屋id的数据
        filters.append(House.id.notin_(conflict_house_ids))

    # 根据不同排序方式去查询
    if sk == "booking":
        house_query = house_query.filter(
            *
            filters).order_by(
            House.order_count.desc())
    elif sk == "price-inc":
        house_query = house_query.filter(*filters).order_by(House.price)
    elif sk == "price-des":
        house_query = house_query.filter(*filters).order_by(House.price.desc())
    else:
        house_query = house_query.filter(
            *
            filters).order_by(
            House.create_time.desc())
    # 获取到分页对象,参数1:第几页数据,参数2:每一页有多少个,参数3是否输出错误
    paginate = house_query.paginate(int(p), HOUSE_LIST_PAGE_CAPACITY, False)
    # 取到当前页的所有对象
    houses = paginate.items
    # 记录总页数
    total_page = paginate.pages

    houses_list = []
    for house in houses:
        houses_list.append(house.to_basic_dict())
    response_dict = {"house": houses_list, "total_page": total_page}
    # 保存房屋数据
    if p <= total_page:  # 当前页如果小于或者等于总页数,再去存
        try:
            redis_key = "house_list_%s_%s_%s_%s" % (
                aid, start_date_str, end_date_str, sk)
            # 获取到管道操作
            pipe = redis_store.pipeline()
            # 开启事务
            pipe.multi()
            # 设置数据
            pipe.hset(redis_key, p, response_dict)
            # 设置指定key的过期时间
            pipe.expire(redis_key, constants.HOUSE_LIST_REDIS_EXPIRES)
            # 提交事务
            pipe.execute()
        except Exception as e:
            current_app.logger.error(e)

    return jsonify(errno=RET.OK, errmsg="OK", data=response_dict)


@api.route('/houses/index')
def get_houses_index():
    """
    首页推荐的房屋最多5个,以订单数量来排序(倒序)
    :return:
    """
    # 尝试从redis缓存中获取数据
    try:
        houses_dict = redis_store.get("home_house_index")
        if houses_dict:
            return jsonify(errno=RET.OK, errmsg="ok", data=eval(houses_dict))
    except Exception as e:
        current_app.logger.error(e)
    # 查询房屋数据:以订单编号倒序排序,最前面5个
    try:
        houses = House.query.order_by(
            House.order_count.desc()).limit(HOME_PAGE_MAX_HOUSES).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询数据失败")

    houses_dict = []
    if houses:
        for house in houses:
            houses_dict.append(house.to_basic_dict())

        # 缓存数据
        try:
            redis_store.set(
                "home_house_index",
                houses_dict,
                HOME_PAGE_DATA_REDIS_EXPIRES)
        except Exception as e:
            current_app.logger.error(e)
    return jsonify(errno=RET.OK, errmsg="OK", data=houses_dict)


@api.route('/houses/<int:house_id>')
def get_house_detail(house_id):
    """
    1.通过house_id查询出房屋
    2.将房屋模型的数据封装到字典中,user_id(取到当前登录用户的id,如果用户没有登录,值为-1表示未登录
    3.直接返回
    4.将房屋数据缓存到redis中
    :param house_id:
    :return:
    """
    user_id = session.get("user_id")
    # 去读取
    try:
        house_dict = redis_store.get("house_detail_%d" % house_id)
        if house_dict:
            return jsonify(
                errno=RET.OK,
                errmsg="OK",
                data={
                    "user_id": user_id,
                    "house": eval(house_dict)})
    except Exception as e:
        current_app.logger.error(e)
    # 通过房屋id查找到具体的房屋信息
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据查询失败")
    if not house:
        return jsonify(errno=RET.NODATA, errmsg="房屋不存在")
    # 生成要返回的信息
    house_dict = house.to_full_dict()
    # 去缓存
    try:
        redis_store.set(
            ("house_detail_%d" %
             house_id),
            house_dict,
            HOUSE_DETAIL_REDIS_EXPIRE_SECOND)
    except Exception as e:
        current_app.logger.error(e)
    return jsonify(
        errno=RET.OK,
        errmsg="OK",
        data={
            "user_id": user_id,
            "house": house_dict})


@api.route('/house/<int:house_id>/images', methods=['POST'])
@login_required
def upload_house_pic(house_id):
    """
    上传房源图片
    :param house_id:
    :return:
    """
    # 取到图片文件
    image_file = request.files.get('house_image')
    if not image_file:
        return jsonify(errno=RET.PARAMERR, errmsg="未选择图片")
    # 尝试查询房屋数据
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询房屋数据失败")
    if not house:
        return jsonify(errno=RET.NODATA, errmsg="未查询到对应房屋")

    # 使用七牛上传图片
    try:
        image_data = image_file.read()
        image_name = storage(image_data)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg="上传图片到七牛失败")
    # 判断房屋是否有主图片,如果没有,则设置
    if not house.index_image_url:
        house.index_image_url = image_name
        db.session.add(house)
    # 生成房屋图片模型并保存至数据库
    house_image = HouseImage()
    house_image.house_id = house_id
    house_image.url = image_name
    try:
        db.session.add(house_image)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存房屋图片失败")
    # 返回数据
    image_url = constants.QINIU_DOMIN_PREFIX + image_name
    return jsonify(errno=RET.OK, errmsg="OK", data={'url': image_url})


@api.route('/house', methods=["POST"])
@login_required
def save_new_house():
    """
    1.获取上传的参数
    2.判断是否为空,校验参数
    3.初始化一个House的对象
    4.进行数据保存
    5.返回结果
    前端发送过来的json数据
    {
        "title":"",
        "price":"",
        "area_id":"1",
        "address":"",
        "room_count":"",
        "acreage":"",
        "unit":"",
        "capacity":"",
        "beds":"",
        "deposit":"",
        "min_days":"",
        "max_days":"",
        "facility":["7","8"]
    }
    :return:
    """
    # 1.获取上传的参数
    user_id = g.user_id
    print(user_id)
    json_dict = request.json
    title = json_dict.get('title')
    price = json_dict.get('price')
    address = json_dict.get('address')
    area_id = json_dict.get('area_id')
    room_count = json_dict.get('room_count')
    acreage = json_dict.get('acreage')
    unit = json_dict.get('unit')
    capacity = json_dict.get('capacity')
    beds = json_dict.get('beds')
    deposit = json_dict.get('deposit')
    min_days = json_dict.get('min_days')
    max_days = json_dict.get('max_days')
    # 2.判断是否为空,校验参数
    if not all([title, price, address, area_id, room_count, acreage,
                unit, capacity, beds, deposit, min_days, max_days]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    try:
        price = int(float(price) * 100)
        deposit = int(float(deposit) * 100)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')

    # 3.初始化house对象
    house = House()
    house.user_id = user_id
    house.area_id = area_id
    house.title = title
    house.price = price
    house.address = address
    house.room_count = room_count
    house.acreage = acreage
    house.unit = unit
    house.capacity = capacity
    house.beds = beds
    house.deposit = deposit
    house.min_days = min_days
    house.max_days = max_days
    # 设置房屋设施
    facilities = json_dict.get("facility")
    if facilities:
        house.facilities = Facility.query.filter(
            Facility.id.in_(facilities)).all()
    # 4.进行数据保存
    try:
        db.session.add(house)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="添加数据失败")
    return jsonify(errno=RET.OK, errmsg="OK", data={"house_id": house.id})


@api.route('/areas')
def get_areas():
    """获取城区信息"""
    # 0. 先从redis中取
    try:
        areas_array = redis_store.get("areas")
        if areas_array:
            return jsonify(
                errno=RET.OK, errmsg="OK", data={
                    "areas": eval(areas_array)})
    except Exception as e:
        current_app.logger.error(e)
    # 1. 获取所有的城区信息
    areas = Area.query.all()
    # 2.因为areas是一个对象的列表,不能直接返回,需要将其转成字典的列表
    areas_array = []
    for area in areas:
        areas_array.append(area.to_dict())
    # 3. 将数据缓存到redis中
    try:
        redis_store.set("areas", areas_array, AREA_INFO_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
    # 4.数据返回
    return jsonify(errno=RET.OK, errmsg="OK", data={"areas": areas_array})
